package cn.felord.boot;

import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class MultiThreadedReaderWithOverlap {
    private static final int NUM_THREADS = 4; // 根据需求调整线程数量
    private static final String TARGET_KEYWORD = "aaa"; // 要统计的关键字

    public static void main(String[] args) throws IOException {
        String filePath = "C:\\Users\\echo\\Desktop\\新建文件夹\\test.txt";
        long fileLength = Files.size(Paths.get(filePath));
        int keywordLength = TARGET_KEYWORD.length();
        long chunkSize = fileLength / NUM_THREADS + keywordLength - 1; // 添加重叠部分

        ExecutorService executorService = Executors.newFixedThreadPool(NUM_THREADS);
        List<Future<Long>> partialCounts = new ArrayList<>();

        for (int i = 0; i < NUM_THREADS; i++) {
            long start = i * chunkSize;
            long end = Math.min((i + 1) * chunkSize, fileLength); // 确保不超过文件长度
            partialCounts.add(executorService.submit(new FileReaderTask(filePath, start, end, keywordLength)));
        }

        long totalCount = 0;
        for (Future<Long> partialCount : partialCounts) {
            try {
                totalCount += partialCount.get();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        executorService.shutdown();
        System.out.println(TARGET_KEYWORD + " 出现次数: " + totalCount);
    }

    // ... 其他方法保持不变 ...

    static class FileReaderTask implements Callable<Long> {
        private final String filePath;
        private final long start;
        private final long end;
        private final int keywordLength;

        public FileReaderTask(String filePath, long start, long end, int keywordLength) {
            this.filePath = filePath;
            this.start = start;
            this.end = end;
            this.keywordLength = keywordLength;
        }

        @Override
        public Long call() throws Exception {
            try (FileChannel fileChannel = FileChannel.open(Paths.get(filePath), StandardOpenOption.READ)) {
                MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, start, end - start);
                long count = 0;
                StringBuilder sb = new StringBuilder();
                while (buffer.hasRemaining()) {
                    char c = (char) buffer.get();
                    sb.append(c);
                    if (sb.length() > keywordLength) {
                        sb.deleteCharAt(0);
                    }
                    if (sb.length() == keywordLength && sb.toString().equals(TARGET_KEYWORD)) {
                        count++;
                    }
                }
                return count;
            }
        }
    }
}